#include "tws_notify/tws_notify.h"
#include "btstack/avctp_user.h"
#include "btstack/bluetooth.h"
#include "classic/tws_api.h"
#include "app_main.h"
#include "earphone.h"
#include "app_config.h"
#include "bt_tws.h"
#include "ble_rcsp_server.h"
#include "tws_dual_conn.h"
#include "user_cfg.h"
#include "tws_dual_share.h"
#include "esco_player.h"
#include "app_testbox.h"
#include "tws_tone_player.h"
#include "debug.h"
#include "os/os_api.h"
#include "spp_online_db.h"

#include "debug.h"
#define LOG_TAG "[TWS_NOTIFY]"

struct tws_notify_packet
{
    u8 header[2];
    u8 packet_len;
    tws_notify_TypeDef type;
    u8 data[32];
};
static spinlock_t notify_lock;

static struct tws_notify_packet packet;

u8 bt_addr_connected[2][7];
u8 *bt_addr_connected_list[2] = {bt_addr_connected[0],bt_addr_connected[1]};
void tws_notify_send_message(void *data,u8 *bt_addr)
{
    int msg[10];
    u8 * byte = (u8*)msg;
    logln_pos();
    memcpy(byte,bt_addr,6);
    byte += 6;
    data+=2; // Goto PacketLen member
    memcpy(byte,data,((u8*)data)[0]);
    // logln_pos("Copy num:%d",((u8*)data)[0]);
    os_taskq_post_type("app_core",MSG_FROM_TWS_NOTIFY,2,msg);
}
static u8 CRC8(u8 *ptr,u8 len)
{
 
    u8 crc;
    u8 i;
    crc = 0;
    while(len--)
    {
       crc ^= *ptr++;
       for(i = 0;i < 8;i++)
       {
           if(crc & 0x80)
           {
               crc = (crc << 1) ^ 0x07;
           }
           else crc <<= 1;
       }
    }
    return crc;
}

void tws_notify_init(void)
{
    spin_lock_init(&notify_lock);
}

__initcall(tws_notify_init);

#define __lock() spin_lock(&notify_lock)
#define __unlock() spin_unlock(&notify_lock)

static inline int pack_data(tws_notify_TypeDef tws_notify, void *data, int len)
{
    u8 crc8;
    packet.header[0] = 0x55;
    packet.header[1] = 0xAA;
    packet.type = tws_notify;
    memcpy(packet.data, data, len);
    packet.packet_len = len + 3; // +notify_type,packet_len+crc8
    crc8 = CRC8(&(packet.packet_len), packet.packet_len-1);
    // logln_info("crc calculated:%x", crc8);
    packet.data[len] = crc8;
    return packet.packet_len;
}

#if 0
/**
 * @brief 请添加该函数实现到 spp_online_db.c 并将声明到本文件能发现的位置
 * @author zhengziyang (zhengziyang@zh-jieli.com)
 */

int spp_send_data(void *remote_addr,u8 *data, u16 len)
{
    if(spp_state == SPP_USER_ST_CONNECT)
    {
        app_spp_set_filter_remote_addr(online_debug_spp_hdl,remote_addr);
        int ret = online_spp_send_data(data, len);
        app_spp_clean_filter_remote_addr(online_debug_spp_hdl);
        return ret;
    }
        
    else
        return 0;
}
#endif

int tws_notify_send(u8 *bt_addr, tws_notify_TypeDef tws_notify, void *data, int len)
{
    int ret = TWS_NOTIFY_ERR_UNKNOWN;
    if(tws_api_get_role() != TWS_ROLE_MASTER)
    {
        return ret;
    }
    __lock();
    int connected_num = btstack_get_conn_devices(bt_addr_connected_list,2);
    logln_pos("connected:%d\nDEV1:"LOG_BT_ADDR_FORMAT"\nDEV2:"LOG_BT_ADDR_FORMAT,connected_num,LOG_BT_ADDR_DATA(bt_addr_connected_list[0]),LOG_BT_ADDR_DATA(bt_addr_connected_list[1]));
    for(int i=0; i<connected_num; i++)
    {
        if(memcmp(bt_addr,bt_addr_connected_list[i],6) == 0)
        {
            logln_pos();
            pack_data(tws_notify,data,len);
#ifdef TWS_NOTIFY_METHOD_SPP
            ret = spp_send_data(bt_addr,(u8*)&packet,packet.packet_len+2);
#else
#endif
            break;
        }
        else
        {
            ret = TWS_NOTIFY_ERR_ADDR_INVALID;
        }
    }
    __unlock();
    return ret;
}

struct tws_notify_recieve_packet
{
    u8 bt_addr[6];
    u8 packet_len;
    tws_notify_TypeDef type;
    u8 data[32];
};

void tws_notify_recieve_callback(void *rec_data,u16 len, u8 *bt_addr)
{
    u8 *data = rec_data,crc8;
    struct tws_notify_packet *recieve_packet;
    if(tws_api_get_role() != TWS_ROLE_MASTER)
    {
        return;
    }
    if(len < 4)
    {
        return;
    }
    if(data[0] != 0x55 || data[1] != 0xAA)
    {
        return;
    }
    recieve_packet = (void*)data;
    crc8 = CRC8(&(recieve_packet->packet_len), recieve_packet->packet_len-1);
    logln_pos("crc8:%d,recieve_packet crc:%d",crc8,recieve_packet->data[recieve_packet->packet_len-3]);
    if(crc8 == recieve_packet->data[recieve_packet->packet_len-3])
    {
        tws_notify_send_message(data,bt_addr);
    }
    return;
}

static void tws_notify_msg_handler(int *msg)
{
    struct tws_notify_recieve_packet *recieve = (struct tws_notify_recieve_packet*)msg;
    u8 a2dp_bt_addr[6];
#ifdef ENABLE_TWS_NOTIFY
    switch(recieve->type)
    {
        case TWS_NOTIFY_COMPETE_BACK:
            if (a2dp_player_get_btaddr(a2dp_bt_addr))
            {
                if (memcmp(a2dp_bt_addr, recieve->bt_addr, 6) == 0) {
                    tws_a2dp_sync_play(recieve->bt_addr, 1);
                } else {
                    tws_a2dp_slience_detect(a2dp_bt_addr,1);
                    tws_a2dp_sync_play(recieve->bt_addr, 1);
                    tws_notify_send(a2dp_bt_addr,TWS_NOTIFY_COMPETED, recieve->bt_addr,6);
                }
            }
            break;

        default:
            break;
    }
#endif
}

APP_MSG_HANDLER(_tws_notify_msg_handler) = 
{
    .owner = 0xff,
    .from = MSG_FROM_TWS_NOTIFY,
    .handler = &tws_notify_msg_handler
};
